Constructors should not be asynchronous because they are meant to initialize an instance of a class synchronously. While you can technically run a
promise in a constructor, the instance will be returned before the asynchronous operation completes, which can lead to potential issues if the rest of
your code expects the object to be fully initialized. While returning the promise may seem the solution for this problem, it is not standard practice
and can lead to unexpected behavior. Returning a promise (or, in general, any object from another class) from a constructor can be misleading and is
considered a bad practice as this leads to unexpected results with inheritance and the instanceof
operator.
class MyClass {
constructor() {
Promise.resolve().then(() => this.data = fetchData()); // Noncompliant, this.data will be undefined in the new instance
}
}
Instead, you can create an asynchronous method that performs the necessary asynchronous operations after the object has been constructed
class MyClass {
constructor() {
this.data = null;
}
async initialize() {
this.data = await fetchData();
}
}
(async () => {
const myObject = new MyClass();
await myObject.initialize();
})();
Otherwise, you can use a static factory method that returns a promise resolving to an instance of the class after performing the asynchronous
operations.
class MyClass {
constructor(data) {
this.data = data;
}
static async create() {
const data = await fetchData();
return new MyClass(data);
}
}
(async () => {
const myObject = await MyClass.create();
})();
Using an asynchronous factory function or an initialization method provides a more conventional, readable, and maintainable approach to handling
asynchronous initialization in JavaScript.